package gitobject;

import sha1.SHA1;
import zlib.ZLibUtils;
import fileoperation.FileReader;
import java.io.*;
import stage.*;
import java.util.*;


public class Tree extends GitObject {
    TreeMap<String, GitObject> treeList = new TreeMap<>(
//            new Comparator<String>() {
//        @Override
//        public int compare(String o1, String o2) {
//            String[] s1 = o1.split("[/|\\\\]");
//            String[] s2 = o2.split("[/|\\\\]");
//            if (s1.length > 1 && s2.length == 1)
//                return -1;
//            else if (s1.length == 1 && s2.length > 1)
//                return 1;
//            else
//                return o1.compareTo(o2);
//        }
//    }
    );

    public TreeMap<String, GitObject> getTreeList() {
        return treeList;
    }

    public Tree() {
        fmt = "tree";
        mode = "040000";
        value = "";
        modified_time = new Date().getTime();
    }

    /**
     * Constructor
     *
     * @param file
     * @throws Exception
     */
    public Tree(File file) throws Exception {
        fmt = "tree";
        mode = "040000";
        value = "";
        modified_time = file.lastModified();
        File[] fs = file.listFiles();
        assert fs != null;
        for (File f : fs) {
            if (f.isDirectory()) {
                Tree tree = new Tree(f);
                treeList.put(f.getName(), tree);
            } else if (f.isFile()) {
                Blob blob = new Blob(f);
                treeList.put(f.getName(), blob);
            }
        }
        treeList.forEach((name, object) -> value += object.mode + " " + object.fmt + " "
                + object.key + " " + name + "\n\r");
        genKey();
        compressWrite();
    }

    public Tree(Index index) throws Exception {
        fmt = "tree";
        mode = "040000";
        value = "";
        modified_time = new Date().getTime();
        genKey(index.getInfo());
        Serialize(this);
    }

    public void Serialize(Tree tree)throws Exception{
        for(GitObject object:tree.treeList.values()){
            if(object.fmt.equals("tree"))
                Serialize((Tree)object);
        }
        tree.compressWrite();
    }
    /**
     * Deserialize a tree object with treeId and its path.
     *
     * @param Id
     * @param Id
     * @throws IOException
     */
    public static Tree deserialize(String Id) throws IOException {
        Tree result = new Tree();
        try {

            String filepath = path + File.separator + Id;
            FileInputStream fis = new FileInputStream(filepath);
            byte[] dcp = ZLibUtils.decompress(fis);
            fis.close();
            ByteArrayInputStream bai = new ByteArrayInputStream(dcp);
            ObjectInputStream ois = new ObjectInputStream(bai);
            bai.close();
            result = (Tree) (ois.readObject());
            ois.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * Sort the files in a certain order. You should consider whether it's a file or a directory.
     *
     * @param fs
     * @return List
     */
    public List sortFile(File[] fs) {
        List fileList = Arrays.asList(fs);
        Collections.sort(fileList, new Comparator<File>() {
            @Override //表示重写方法
            public int compare(File o1, File o2) {
                if (o1.isDirectory() && o2.isFile())
                    return -1;
                else if (o1.isFile() && o2.isDirectory())
                    return 1;
                else
                    return o1.compareTo(o2);
            }
        });
        return fileList;
    }

    /**
     * Generate the key of a tree object.
     *
     * @return String
     * @throws Exception
     */
    public void genKey() throws Exception {
        key = SHA1.getHash(value);
    }

    public void genKey(Map<String, String[]> info) throws Exception {
        for (String path : info.keySet()) {
            String[] splitPath = path.split("[/|\\\\]");
            insert(splitPath, info.get(path));
        }
    }

    public void insert(String[] path, String[] info) throws Exception {
        if (path.length == 1) {
            Blob blob = Blob.deserialize(info[1]);
            treeList.put(path[0], blob);
        } else {
            String[] newPath = new String[path.length - 1];
            System.arraycopy(path, 1, newPath, 0, path.length - 1);
            Tree tree;
            if (!treeList.containsKey(path[0])) {
                tree = new Tree();
                tree.insert(newPath, info);
                treeList.put(path[0], tree);
            } else {
                tree = (Tree) treeList.get(path[0]);
                tree.insert(newPath, info);
            }
        }
        value = "";
        treeList.forEach((name, object) -> value += object.mode + " " + object.fmt + " " + object.key + " " + name + "\n\r");
        genKey();
    }

    @Override
    public String toString() {
        return "040000 tree " + key;
    }
}
